#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "../capture.h"

#define TCPDUMP_MAGIC          0xa1b2c3d4
#define PCAP_VERSION_MAJOR 2
#define PCAP_VERSION_MINOR 4
#define DLT_EN10MB     1     // Ethernet (10Mb)
#define LINKTYPE_ETHERNET     DLT_EN10MB     //also for 100Mb and up
#define DEFAULT_SNAPLEN 68     /// ether + IPv4 + TCP + 14

// #define true 1
// #define flase 0
#define FILESIZETRIGGER 11000
#define FILESIZE 16777216

struct pcap_file_header
{
    uint32_t magic;
    uint16_t version_major;
    uint16_t version_minor;
    int32_t thiszone;         //gmt to local correction
    uint32_t sigfigs;          //accuracy of timestamps
    uint32_t snaplen;          //max length saved portion of each pkt
    uint32_t linktype;         //data link type (LINKTYPE_*)
};

struct pcap_pkthdr
{
    struct timeval ts;      // time stamp
    uint32_t   caplen;         // length of portion present
    uint32_t   len;            // length this packet (off wire)
};


int capture_init(struct capture* c, const char* filename, struct lock* l)
{

    struct pcap_file_header filehdr;
    FILE* fp = 0;

    strcpy(c->file, filename);
    c->l = l;

    /* write pcap header. */
    if (0 == (fp = fopen(c->file, "w+")))
    {
        fprintf(stderr, "capture_init(): Cannot open file %s for write.", c->file);
        return 0;
    }

    filehdr.magic = TCPDUMP_MAGIC;
    filehdr.version_major = PCAP_VERSION_MAJOR;
    filehdr.version_minor = PCAP_VERSION_MINOR;

    filehdr.thiszone = time(NULL);      //thiszone;
    filehdr.snaplen = DEFAULT_SNAPLEN;  //snaplen;
    filehdr.sigfigs = 0;
    filehdr.linktype = LINKTYPE_ETHERNET;

    fwrite(&filehdr, sizeof(struct pcap_file_header), 1, fp);
    fclose(fp);
}

static inline int capture_lock(struct capture* p)
{
    if (p->l) 
    {
        return p->l->lock_fp(p->l);
    }
    return 1;
}

static inline int capture_unlock(struct capture* p)
{
    if (p->l) 
    {
        return p->l->unlock_fp(p->l);
    }
    return 1;
}


static inline void dump_pcapfile(FILE* fd, const struct pcap_pkthdr* ph, uint8_t* packet)
{
    (void)fwrite((char*)ph, sizeof(struct pcap_pkthdr), 1, fd);
    (void)fwrite((char*)packet, ph->caplen, 1, fd);
}

void capture_write(struct capture* pk, uint8_t* pkt, unsigned short pkt_len)
{
    FILE* fp = 0;
    struct pcap_pkthdr pkthdr;
    struct timeval l_timeval;

    capture_lock(pk);

    if (0 == (fp = fopen(pk->file, "a+")))
    {
        // fprintf(stderr, "Cannot open file %s for write.", pcap_file_name);
        fprintf(stderr, "Cannot open file %s for write.", pk->file);
        capture_unlock(pk);
        return;
    }

    fseek(fp, 0, SEEK_END);

    gettimeofday(&l_timeval, NULL);

    pkthdr.ts = l_timeval;
    pkthdr.caplen = pkt_len;
    pkthdr.len = pkthdr.caplen;

    dump_pcapfile(fp, &pkthdr, pkt);
    fclose(fp);

    capture_unlock(pk);
}

